/**
 * @author sunliusen
 * @param url 视频地址
 * @returns {Array<{}>} base64: 视频解析到每秒的图片
 * @returns {Array<{}>} box: faceapi解析的位置
 * @returns {Array<{}>} clipImage: 通过box裁剪后的图片
 * @returns {Array<{}>} img: base64加载的img
 * @returns {Array<{}>} second: 在当前视频中的秒
 * */
class ClipImages {
  [Symbol("ClipImages")] = "裁剪人物";
  numb = 0;
  time;
  constructor(url) {
    this.time = setInterval(() => {
      this.numb = this.numb + 1;
    }, 1000);
    return this.initWeights(url);
  }
  async initWeights(url) {
    await faceapi.nets.tinyFaceDetector.loadFromUri(
      "./face-api.js-master/weights"
    );
    return await this.install(url);
  }
  async install(url) {
    let data = await this.getVideoFace(url);
    const detectFrame = async (img) => {
      let box;
      const detections = await faceapi.detectAllFaces(
        img,
        new faceapi.TinyFaceDetectorOptions()
      );
      detections.forEach((detection) => {
        box = detection.box;
      });
      return box;
    };
    data = data.map((item) => {
      return new Promise((resolve, reject) => {
        let img = new Image();
        img.onload = async () => {
          item.box = await detectFrame(img);
          item.img = img;
          resolve(item);
        };
        img.src = item.base64;
      });
    });
    data = await Promise.all(data);
    console.log(`本次处理耗时：${this.numb}秒`);
    clearInterval(this.time);
    return data
      .filter((i) => Boolean(i.box))
      .map((item) => {
        item.clipImage = this.getClipImage(item.box, item.img);
        return item;
      });
  }
  async getVideoFace(url) {
    const video = document.createElement("video");
    const canvas = document.createElement("canvas");
    video.src = url;
    await new Promise((resolve) => {
      video.addEventListener("loadedmetadata", () => {
        resolve();
      });
    });
    const duration = video.duration;
    const ctx = canvas.getContext("2d");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const frameData = [];
    for (let i = 0; i < duration; i++) {
      video.currentTime = i;
      await new Promise((resolve) => {
        video.addEventListener("seeked", function handler() {
          video.removeEventListener("seeked", handler);
          ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
          const base64 = canvas.toDataURL("image/jpeg");
          frameData.push({
            base64,
            second: i,
          });
          resolve();
        });
      });
    }

    return frameData;
  }

  getClipImage(box, image) {
    const newCanvas = document.createElement("canvas");
    const newCtx = newCanvas.getContext("2d");
    newCanvas.width = box.width;
    newCanvas.height = box.height;
    newCtx.drawImage(
      image,
      box.x,
      box.y,
      box.width,
      box.height,
      0,
      0,
      box.width,
      box.height
    );
    const base64Data = newCanvas.toDataURL("image/png");
    let img = document.createElement("img");
    img.src = base64Data;
    return base64Data;
  }
}

function base64ToBlob(base64, contentType = "image/png") {
  // 去掉 Base64 编码字符串的前缀
  const sliceIndex = base64.indexOf(",") + 1;
  const base64Data = base64.slice(sliceIndex);

  // 解码 Base64 数据
  const binary = atob(base64Data);
  const length = binary.length;
  const buffer = new ArrayBuffer(length);
  const view = new Uint8Array(buffer);

  // 将二进制字符串转换为 Uint8Array
  for (let i = 0; i < length; i++) {
    view[i] = binary.charCodeAt(i);
  }

  // 创建 Blob 对象
  return new Blob([view], { type: contentType });
}
